部署上线、监控接线与发布治理
这一章记录 StoryCam 从“准备上线”到“生产基础设施打通”的过程:先用方案澄清边界,再补齐 P0 生产能力,最后落到 dev → main → release、Render、Supabase、Cloudflare、Sentry 和 uptime 的上线链路。
TL;DR
用户从“看看还缺什么”开始,逐步把 StoryCam 的部署边界、生产能力、发布流程和运维监控都推到可执行层面。
用户明确要求关掉页面后继续生成并保存,生产必须是真实 final MP4,这直接推动了 worker-owned jobs 和 async final_work 的设计。
首版没有拆成 Vercel 前端 + Render 后端,而是 Render Web + Worker 承担 Next.js UI、API、后台任务和 ffmpeg final MP4。
用户明确要求 push 后先 PR 到 dev,再从 dev PR 到 main,不能跳过 dev;Render 随 main 自动部署,release/tag 跟 main 对齐。
Render、Supabase、Google OAuth、Cloudflare、自定义域名、Sentry 独立项目、issue alerts、GitHub uptime/deep health 都被推进并验证。
还需要跑低成本真实 provider smoke、验证 ffmpeg 生产稳定性、决定是否补 staging、补 Render 告警并更新文档状态。
本章学习目标
不要只问“部署到哪里”,要问用户是否会关页、是否需要真实产物、是否要跨地区访问、是否能接受直接生产 beta。
先保证可部署、可恢复、可观测、可控成本,再把 analytics、admin、自动 canary 和成本 dashboard 放进后续。
CI、PR review、dev → main、release/tag、自动部署和 uptime 不是形式,是生产系统的一部分。
OAuth 跳 localhost 的截图不是“偶发 UI 问题”,而是 Google / Supabase / app URL 配置链路不一致的证据。
工具、参考图和可视化证据
GitHub PR / Actions、Render CLI/API、Supabase CLI、Google Cloud CLI、Cloudflare Wrangler 与 Dashboard、Sentry。
code-simplifier、gstack-ship、GitHub code review / CI 修复流程、部署与上线检查思路。
docs/DEPLOYMENT.md、docs/OBSERVABILITY.md、render.yaml、scripts/storycam-worker.ts、scripts/storycam-verify-live.mjs。
关键截图证据:OAuth 回调落到 localhost
聊天中出现一张浏览器截图:地址栏显示 https://localhost:10000,页面返回 {"info":"Invalid request!"},用户说明“退出账号后重新总会先出现截图的问题,退回来显示登录成功了”。这张图的意义不是展示 UI,而是证明生产登录链路中存在 canonical URL / redirect URL 配置漂移。
此处为文字化复刻,不嵌入原截图;没有臆造截图之外的信息。
沿时间排列的原始 Prompt
阶段 1:先出部署方案,不改代码
阶段 2:架构选择与 P0/P1 切分
阶段 3:沉淀文档与实施 P0
阶段 4:部署配置、环境变量与 OAuth 修复
阶段 5:发布纪律、监控与剩余上线清单
时间线
关键时刻
Render 全栈优先
- 当时的问题
- 是否需要 Vercel 承担前端,Render 只承担当后端。
- 为什么重要
- StoryCam 的 UI、API、auth callback、session、jobs、download route 在一个同源边界里更安全、更简单。
- 最终处理
- 首版使用 Render Web + Worker;Vercel 暂不进入核心应用部署。
关页后继续生成
- 当时的问题
- 如果 generation job 依赖浏览器 polling 推进,用户关页会中断体验。
- 为什么重要
- AI 视频生成是长耗时任务,用户天然会离开页面。
- 最终处理
- 引入 worker-owned jobs、锁、run_after、claim RPC,让浏览器只观察状态。
OAuth 的 localhost 漂移
- 当时的问题
- 用户退出重登会先看到 localhost invalid request,再返回成功。
- 为什么重要
- 这暴露出生产 canonical URL 和 OAuth redirect 配置未完全一致。
- 最终处理
- 沿 Google Cloud、Supabase、Render、Cloudflare 链路修复,并加入 uptime 检查。
Cloudflare 不是成本控制的全部
- 当时的问题
- Cloudflare rate-limit 权限和 plan 有限制,只能做短周期 burst 防护。
- 为什么重要
- AI provider 成本来自登录用户动作,不能只靠 IP 层规则。
- 最终处理
- Cloudflare 做边缘防护,服务端 per-user quota 才是主要成本控制。
关键决策表
| 方案 | 当时看起来的好处 | 为什么放弃或保留 | 最终选择 |
|---|---|---|---|
| Vercel 前端 + Render 后端 | 常见 Next.js 部署组合,前端 CDN 体验好。 | 会增加跨域 cookie、CORS、OAuth redirect、CSRF、media URL 复杂度;对 durable generation 没有帮助。 | 放弃首版拆分;保留未来营销站可能性。 |
| Render Web + Worker 全栈 | 同源边界清晰,Web/API/Auth/Worker/ffmpeg 在同一生产平台。 | 更符合 StoryCam 的 MVP 复杂度;需要验证 Native Runtime ffmpeg。 | 采用。 |
| 浏览器 polling 推进任务 | 实现简单,适合本地 demo。 | 用户关页会影响任务进度,不符合生产体验。 | 放弃作为进度来源;保留只读状态观察。 |
| 后台 worker claim jobs | 任务可在用户离开后继续,支持锁、重试、延迟轮询。 | 需要 DB 字段、RPC、worker lifecycle 和 terminal state 防护。 | 采用为 P0。 |
| 直接生产 beta | 更快开始真实验证,减少环境搭建时间。 | 风险更高,需要 uptime、deep health、canary、rollback 和监控兜底。 | 暂时接受;staging 完整环境列为待确认。 |
| PostHog / Admin 首版上线 | 更好观察 funnel 和人工排障。 | 不是打开 beta 的最低门槛,容易拉大 P0 范围。 | 推到 P1。 |
可复用方法
上线约束四问
在部署前问清:谁访问、从哪里访问、关页后怎样、最终产物是什么。
用户范围 → 地域入口 → 生命周期 → 产物标准异步任务生产化检查
凡是超过几秒的 AI 任务,都要确认是否 durable、可恢复、可重试、可取消、可观测。
claim → lock → run_after → terminal state → restore配置 bug 排查链
OAuth、域名、回调问题先不要改业务代码,先沿外部平台配置链路逐段验证。
症状 → URL 证据 → 平台配置 → 回调验证P0/P1 截断法
P0 只保留“不能上线就会失败”的能力;P1 放提升运营效率但不阻塞 beta 的能力。
可部署 + 可恢复 + 可观测 + 可控成本发布流程闭环
不要把 merge 当终点。生产发布要覆盖分支、CI、PR、release、deploy、health、monitor。
dev → main → release → deploy → uptime边缘防护分层
Cloudflare 适合挡异常流量和缓存静态资源;业务成本控制必须回到服务端用户级配额。
WAF / cache / burst limit + per-user quota工程证据
PR / Branch / Release
- 流程:feature →
dev→main - PR:记录到
#29由 dev 合并到 main - 当时部署 commit:
3072c1e - Release:
v0.1.1.2一度落后于 main,需要补发新版 release - Checks:CI 曾失败,修复后继续;Production Uptime 后续通过
Deploy / Runtime
- Render Web:
storycam-web - Render Worker:
storycam-worker - 区域:Singapore
- Runtime:Native Runtime 暂用,ffmpeg 待真实 smoke 确认
- 自定义域名:
storycam.znbuild.com
Cloudflare / Uptime
- DNS:Proxied
- Static cache:Next.js static asset 检查命中
HIT - Dynamic bypass:
/api/*、/auth/*、authenticated paths - Rules:基础 WAF 和生成 endpoint burst limit
- GitHub Uptime:public health、deep health、auth callback、static cache
Sentry / 安全
- 独立项目:
storycam/storycam - 不放在
geo-app - Issue alerts:新问题、回归、频率异常
- 上下文脱敏:禁止 prompt、signed URL、provider body、secret
- 所有密钥:
[REDACTED]
文件 / 脚本
docs/DEPLOYMENT.mddocs/OBSERVABILITY.mdrender.yamlscripts/storycam-worker.tsscripts/storycam-verify-live.mjs- DeepSeek / OpenRouter / Seedance smoke scripts
命令类别
pnpm storycam:verify:live
pnpm storycam:smoke:deepseek
pnpm storycam:smoke:openrouter
pnpm storycam:smoke:seedance
pnpm worker:storycam
命令作为工程证据列出;不包含任何 token、DSN 或 provider payload。
后续事项
已完成
- 部署方案文档化。
- P0 开发计划形成并实施。
- Render Web / Worker 建立并随 main 部署。
- Google OAuth、Supabase、Cloudflare 域名链路修复和验证。
- Sentry 独立项目、issue alerts、GitHub uptime/deep health 配置。
- Cloudflare cache/WAF/rate-limit 基础规则落地。
待确认
- 真实生产 smoke:文本、图片、视频、ffmpeg final MP4。
- 关页后 worker 继续生成,重新登录 restore 并下载真实 MP4。
- Native Runtime ffmpeg 稳定性;必要时切 Docker。
- 是否补齐完整 staging 环境。
- Render dashboard 平台告警是否全部配置。
- release/tag 与当前 main 部署状态对齐。
后续开发
- PostHog safe events 和 funnel 分析。
- 内部
/admin,查看 job / provider failure / 用户级状态。 - 自动 post-deploy canary。
- provider 成本和失败率 dashboard。
- stuck job 手动 retry / cancel 工具。
- 把已完成 observability plan 从 active 移到 completed,并同步部署文档状态。